package cn.learn.util;


import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * redis的工具类
 *
 * @author huangyezhan
 * @version 1.0
 * @date 2020年01月07日23:33
 */
@Component
public class RedisUtil {
    /**
     * 默认过期时间（多少秒后过期）半小时
     */
    private static final long DEFAULT_EXPIRE_TIME = 30 * 60L;

    private final StringRedisTemplate stringRedisTemplate;

    public RedisUtil(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }


    /**
     * 写入redis，string数据类型，默认30分钟
     *
     * @param key   写入的key
     * @param value 存储的数据
     * @return 插入成功true，否则false
     */
    public boolean saveValue(final String key, Object value) {
        return saveValue(key, value, DEFAULT_EXPIRE_TIME);
    }

    /**
     * 写入redis，string数据类型，有过期时间
     *
     * @param key        写入的key
     * @param value      存储的数据
     * @param expireTime 过期时间，多少秒后过期，单位是（秒s）
     * @return 插入成功true，否则false
     */
    public boolean saveValue(final String key, Object value, long expireTime) {
        boolean result = false;
        try {
            ValueOperations<String, String> opsForValue = stringRedisTemplate.opsForValue();
            opsForValue.set(key, "jsonString", expireTime, TimeUnit.SECONDS);
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /*
     * ==========================================================================================================================================================================
     * ============================================================================== hash数据类型 ===============================================================================
     * hash类型用来存储对象最佳
     * 在实际的开发中为了不让Redis占用内存较大，所以在使用Redis哈希类型的时候，尽量不要创建过多的键。
     * 我们知道Redis哈希类型的内部编码有ziplist和hashtable两种，并且在符合某些条件的情况下，这两种编码会自动转换。
     * 当Redis哈希类型的内部编码变成hashtable时，会比ziplist更消耗内存，在这一点要特别注意。
     * ==========================================================================================================================================================================
     */

    /**
     * 写入redis，hash类型的数据
     *
     * @param redisKey 存在redis里面的key
     * @param hashKey  属性的key，现在这里放对象的key
     * @param o        属性的值，现在这里直接就存放整个对象
     */
    public void saveHash(final String redisKey, final String hashKey, Object o) {
        HashOperations<String, String, Object> opsForHash = stringRedisTemplate.opsForHash();
        String                                 jsonString = JsonUtil.obj2String(o);
        opsForHash.put(redisKey, hashKey, jsonString);
    }

    /**
     * 指定key获取对应的对象信息
     *
     * @param redisKey 存在redis里面的key
     * @param hashKey  属性的key，现在这里放对象的key
     * @return 返回查询出来的对象
     */
    public Object getHash(final String redisKey, final String hashKey) {
        HashOperations opsForHash = stringRedisTemplate.opsForHash();
        Object         o          = opsForHash.get(redisKey, hashKey);
        return o;
    }

    /**
     * 指定key获取对应的对象信息
     *
     * @param redisKey 存在redis里面的key
     * @param hashKey  属性的key，现在这里放对象的key
     * @param clz      指定数据类型
     * @param <T>      泛型
     * @return 返回泛型指定的数据类型对象
     */
    public <T> T getHash(final String redisKey, final String hashKey, Class<T> clz) {
        String o = (String) this.getHash(redisKey, hashKey);
        return o == null ? null : JsonUtil.string2Obj(o, clz);
    }

    /**
     * 查询看是否有指定的hash对象
     *
     * @param redisKey 存在redis里面的key
     * @param hashKey  属性的key，现在这里放对象的key
     * @return true为有改对象
     */
    public Boolean existsHashKey(final String redisKey, final String hashKey) {
        HashOperations opsForHash = stringRedisTemplate.opsForHash();
        Boolean        hasKey     = opsForHash.hasKey(redisKey, hashKey);
        return hasKey;
    }

    /**
     * 删除hash对象
     *
     * @param redisKey 存在redis里面的key
     * @param hashKey  属性的key，现在这里放对象的key
     * @return 返回删除数据的条数
     */
    public Long deleteHash(final String redisKey, String... hashKey) {
        HashOperations opsForHash = stringRedisTemplate.opsForHash();
        Long           delete     = opsForHash.delete(redisKey, hashKey);
        return delete;
    }


}
